package nl.weeaboo.sh.danmaku;

import static nl.weeaboo.sh.danmaku.SpellUtil.fastCos;
import static nl.weeaboo.sh.danmaku.SpellUtil.fastSin;

import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;

import javax.media.opengl.GL;

import nl.weeaboo.game.gl.GLManager;
import nl.weeaboo.sh.model.ColCircle;
import nl.weeaboo.sh.view.CharaImage;
import nl.weeaboo.sh.view.anim.Animation;

public class ShotModel {

	private Object owner;
	private SpellBook spellbook;
	
	int colType;
	boolean killed;
	float x, y;
	ColNode colNodes[];
	int colNodesL;
	boolean visible;
	
	private Animation anim;
	private boolean colNodesDirty;
	private int power;
	private int hp;
	private boolean solid;
	
	private boolean speedDirty;
	private float speed;
	private float speedX, speedY;
	private float angle;
	private float angleInc;
	
	public ShotModel(Animation anim, int colType, SpellBook t) {
		this.anim = anim;
		this.colType = colType;
		this.spellbook = t;
		
		colNodes = new ColNode[0];
		colNodesL = 0;
		colNodesDirty = true;

		hp = 1;
		visible = true;
		setPower(5);
		
		speedDirty = true;		
	}
	public ShotModel(ShotModel s) {
		this(s.anim, s.colType, s.spellbook.clone());
		
		owner = s.owner;
		x = s.x;
		y = s.y;		
		hp = s.hp;
		visible = s.visible;
		
		speedDirty = false;
		speed = s.speed;
		speedX = s.speedX;
		speedY = s.speedY;
		angle = s.angle;
		angleInc = s.angleInc;
	}
	
	//Functions
	public ShotModel clone() {
		return new ShotModel(this);
	}
	
	public void destroy() {
		kill();
	}
	public void kill() {
		killed = true;				
	}
	
	public void advance(double forward) {
		advance(forward, 0);
	}
	public void advance(double forward, double side) {
		if (Math.abs(forward) >= 0.001f) {
			x += fastSin(angle) * forward;
			y -= fastCos(angle) * forward;
		}

		if (Math.abs(side) >= 0.001f) {
			x += fastCos(angle) * side;
			y -= fastSin(angle) * side;
		}
	}

	public void step(Universe u) {
		anim = anim.update(1);
		
		if (!spellbook.finished) {
			spellbook.step(u, null, this);
		}
		
		if (angleInc != 0) {
			angle += angleInc;
			colNodesDirty = true;
			speedDirty = true;
			
			while (angle > 512f) angle -= 512f;
			while (angle < 0) angle += 512.0f;
		}
		
		if (speedDirty) {
			speedX =  fastSin(angle) * speed;
			speedY = -fastCos(angle) * speed;
			speedDirty = false;
		}
		
		x += speedX;
		y += speedY;
		
		if (colNodesDirty) {
			updateColNodes();			
		}
		
		u.updateShotPosition(this);

		if (anim != null) {
			Rectangle imageBounds = anim.getImageBounds();
			int r = Math.max(imageBounds.width, imageBounds.height);
			if (x < -r || y < -r || x >= u.rw+r || y >= u.rh+r) {
				kill();
			}
		}
	}
	
	protected void updateColNodes() {
		Object img = anim.getCurrentFrame().getImage();
		if (!(img instanceof CharaImage)) {
			colNodesL = 0;
			return;
		}
		
		CharaImage image = (CharaImage)img;
		ColCircle c[] = image.getColCircles();
		
		//Resize array if too small
		if (colNodes.length < c.length) {
			colNodes = new ColNode[c.length];
			for (int n = 0; n < colNodes.length; n++) {
				colNodes[n] = new ColNode(this, colType);
			}
		}
		
		colNodesL = c.length;
		
		//Update array elements
		float cos = fastCos(angle);
		float sin = fastSin(angle);
		for (int n = 0; n < colNodesL; n++) {
			colNodes[n].radius   = c[n].getRadius();
			colNodes[n].radiusSq = c[n].getRadiusSquared();
			
			colNodes[n].x = cos * c[n].x - sin * c[n].y;
			colNodes[n].y = sin * c[n].x + cos * c[n].y;
			//System.out.println(angle + " " + cx + " " + cy + " " + ix + " " + iy);				
		}
	}
	
	public void draw(GLManager glm) {
		GL gl = glm.getGL();
		gl.glPushMatrix();			
		gl.glTranslated(x, y, 0);
		gl.glRotatef(SpellUtil.angleToDegrees(angle), 0, 0, -1);
		
		anim.draw(glm, false);
		
		gl.glPopMatrix();		
	}
	
	public void damage(int dmg) {
		setHp(hp - Math.max(0, dmg));
	}
	
	//Getters
	public Object getOwner() { return owner; }
	public int getColType() { return colType; }
	public int getHp() { return hp; }
	public boolean isSolid() { return solid; }
	public float getX() { return x; }
	public float getY() { return y; }
	public float getSpeed() { return speed; }
	public float getAngle() { return angle; }
	public float getAngleInc() { return angleInc; }
	public int getPower() { return power; }
	public boolean isVisible() { return visible; }
	public void getImageBounds(Rectangle2D.Float r) {
		Rectangle ib = anim.getImageBounds();
		r.x = x+ib.x;
		r.y = y+ib.y;
		r.width = ib.width;
		r.height = ib.height;
	}
	
	//Setters
	public void setHp(int h) {
		if (hp > 0 && h <= 0) {
			hp = h;			
			destroy();
		} else {
			hp = h;
		}
	}
	public void setAnimation(Animation a) {
		if (anim != a) {
			anim = a;
			colNodesDirty = true;
		}
	}
	public void setSolid(boolean s) {
		solid = s;
	}
	public void setPower(int p) {
		power = p;
	}
	public void setPos(float x, float y) { this.x = x; this.y = y; }
	public void setSpeed(float s) {
		speed = s;
		speedDirty = true;
	}
	public void setAngle(float a) {
		angle = a;

		while (angle > 512f) angle -= 512f;
		while (angle < 0) angle += 512.0f;

		speedDirty = true;
		colNodesDirty = true;
	}
	public void setAngleInc(float ai) {
		this.angleInc = ai;
	}
	public void setVisible(boolean v) {
		this.visible = v;
	}
	
}
